'use strict';

const Service = require('egg').Service;
const BaseService = require('./base');
const TravelPlan = require('../model/travel_plan');
const City = require('../model/city');
const DailyPlan = require('../model/daily_plan');
const DailyPlanItem = require('../model/daily_plan_item');

class TravelPlanService extends Service {
  constructor(ctx) {
    super(ctx);
    this.base = new BaseService(ctx, TravelPlan);
  }

  // 列表（支持按条件过滤）
  async list(where = {}) {
    const rows = await this.base.list(where || {}, {
      include: [{ model: City, as: 'city', attributes: ['id', 'name'] }],
    });
    return rows.map(this.toDTO);
  }

  // 详情（包含每日计划与行程项）
  async getById(id) {
    const plan = await TravelPlan.findByPk(id, {
      include: [
        { model: City, as: 'city', attributes: ['id', 'name'] },
        {
          model: DailyPlan,
          as: 'dailyPlans',
          include: [{ model: DailyPlanItem, as: 'items' }],
          order: [['day', 'ASC']],
        },
      ],
      order: [
        [{ model: DailyPlan, as: 'dailyPlans' }, 'day', 'ASC'],
        [{ model: DailyPlan, as: 'dailyPlans' }, { model: DailyPlanItem, as: 'items' }, 'order_index', 'ASC'],
      ],
    });
    if (!plan) return null;
    return this.toDTO(plan);
  }

  // 创建（支持传入 dailyPlans 结构）
  async create(payload, userId = null) {
    const t = await TravelPlan.sequelize.transaction();
    try {
      const data = this.toModel(payload, userId);
      const created = await TravelPlan.create(data, { transaction: t });

      // 若传入每日计划，则批量创建
      if (Array.isArray(payload.dailyPlans) && payload.dailyPlans.length > 0) {
        for (const dp of payload.dailyPlans) {
          const createdDP = await DailyPlan.create({
            plan_id: created.id,
            day: dp.day,
            date: dp.date ?? null,
            city_name: dp.cityName ?? null,
            note: dp.note ?? null,
          }, { transaction: t });

          const locations = Array.isArray(dp.locations) ? dp.locations : [];
          for (let i = 0; i < locations.length; i++) {
            const l = locations[i];
            await DailyPlanItem.create({
              daily_plan_id: createdDP.id,
              name: l.name ?? '',
              type: l.type ?? 'custom',
              time: l.time ?? null,
              note: l.note ?? null,
              order_index: i,
            }, { transaction: t });
          }
        }
      }

      await t.commit();
      const full = await this.getById(created.id);
      return full;
    } catch (e) {
      await t.rollback();
      throw e;
    }
  }

  // 更新（若包含 dailyPlans 则替换整个每日计划集合）
  async update(id, payload) {
    const t = await TravelPlan.sequelize.transaction();
    try {
      // 先更新主计划字段
      const data = this.toModel(payload);
      if (Object.keys(data).length > 0) {
        await TravelPlan.update(data, { where: { id }, transaction: t });
      }

      // 如果传入 dailyPlans，则进行增量更新：尽量保留每日计划ID，避免破坏已关联路线
      if (Array.isArray(payload.dailyPlans)) {
        // 读取现有每日计划（含行程项）
        const existingDps = await DailyPlan.findAll({ where: { plan_id: id }, transaction: t });
        const existingMap = new Map(existingDps.map(d => [d.id, d]));
        const remainingExistingIds = new Set(existingDps.map(d => d.id));

        // 逐个处理前端传入的每日计划
        for (const dp of payload.dailyPlans) {
          const locations = Array.isArray(dp.locations) ? dp.locations : [];

          // 若包含有效ID且存在于数据库中，则更新该记录并替换其行程项
          if (dp.id && existingMap.has(dp.id)) {
            await DailyPlan.update({
              day: dp.day,
              date: dp.date ?? null,
              city_name: dp.cityName ?? null,
              note: dp.note ?? null,
            }, { where: { id: dp.id }, transaction: t });

            // 先清空旧的 items，再按传入顺序重建（保持简单可靠）
            await DailyPlanItem.destroy({ where: { daily_plan_id: dp.id }, transaction: t });
            for (let i = 0; i < locations.length; i++) {
              const l = locations[i];
              await DailyPlanItem.create({
                daily_plan_id: dp.id,
                name: l.name ?? '',
                type: l.type ?? 'custom',
                time: l.time ?? null,
                note: l.note ?? null,
                order_index: i,
              }, { transaction: t });
            }

            // 该ID已被使用，不需要删除
            remainingExistingIds.delete(dp.id);
          } else {
            // 新增每日计划（无ID或ID不存在）
            const createdDP = await DailyPlan.create({
              plan_id: id,
              day: dp.day,
              date: dp.date ?? null,
              city_name: dp.cityName ?? null,
              note: dp.note ?? null,
            }, { transaction: t });

            for (let i = 0; i < locations.length; i++) {
              const l = locations[i];
              await DailyPlanItem.create({
                daily_plan_id: createdDP.id,
                name: l.name ?? '',
                type: l.type ?? 'custom',
                time: l.time ?? null,
                note: l.note ?? null,
                order_index: i,
              }, { transaction: t });
            }
          }
        }

        // 删除前端未包含的旧每日计划及其行程项
        if (remainingExistingIds.size > 0) {
          const idsToRemove = Array.from(remainingExistingIds);
          await DailyPlanItem.destroy({ where: { daily_plan_id: idsToRemove }, transaction: t });
          await DailyPlan.destroy({ where: { id: idsToRemove }, transaction: t });
        }

        // 同步 days 字段
        await TravelPlan.update({ days: payload.dailyPlans.length }, { where: { id }, transaction: t });
      }

      await t.commit();
      const full = await this.getById(id);
      return full;
    } catch (e) {
      await t.rollback();
      return null;
    }
  }

  // 删除
  async remove(id) {
    const affected = await this.base.deleteById(id);
    return affected > 0;
  }

  /**
   * 审核旅行计划
   * @param {number} planId - 旅行计划ID
   * @param {string} status - 审核状态: approved 或 rejected
   * @param {string} reason - 拒绝原因（可选）
   */
  async auditPlan(planId, status, reason = '') {
    try {
      const plan = await TravelPlan.findByPk(planId);
      if (!plan) {
        return {
          success: false,
          message: '旅行计划不存在'
        };
      }

      // 更新审核状态
      await plan.update({
        status,
        audit_reason: reason || null,
        published_at: status === 'approved' ? new Date() : null
      });

      return {
        success: true,
        message: status === 'approved' ? '审核通过' : '已拒绝',
        data: this.toDTO(plan)
      };
    } catch (error) {
      this.ctx.logger.error('审核旅行计划失败:', error);
      return {
        success: false,
        message: '审核失败: ' + error.message
      };
    }
  }

  // 入库模型转换（不再保存 daily_plans JSON）
  toModel(payload, userId = null) {
    const model = {};
    if (userId ?? payload.userId) model.user_id = userId ?? payload.userId;
    if (payload.cityId !== undefined) model.city_id = payload.cityId;
    if (payload.title !== undefined) model.title = payload.title;
    if (payload.description !== undefined) model.description = payload.description;
    if (payload.startDate !== undefined) model.start_date = payload.startDate ?? null;
    if (payload.isPublic !== undefined) model.is_public = payload.isPublic;
    if (payload.status !== undefined) model.status = payload.status ?? (payload.isPublic ? 'pending' : null);
    if (payload.coverImage !== undefined) model.cover_image = payload.coverImage ?? null;
    if (payload.days !== undefined) model.days = payload.days;
    if (payload.is_top !== undefined) model.is_top = payload.is_top;
    else if (Array.isArray(payload.dailyPlans)) model.days = payload.dailyPlans.length;
    return model;
  }

  // 出库数据转换（拼装 dailyPlans 与 locations）
  toDTO(plan) {
    const plain = plan.toJSON();
    const cityName = plain.city?.name || null;

    let dailyPlans = [];
    if (Array.isArray(plain.dailyPlans)) {
      dailyPlans = plain.dailyPlans
        .sort((a, b) => (a.day || 0) - (b.day || 0))
        .map(dp => ({
          id: dp.id,
          day: dp.day,
          date: dp.date,
          cityName: dp.city_name || cityName || '',
          note: dp.note || '',
          locations: Array.isArray(dp.items)
            ? dp.items
              .sort((a, b) => (a.order_index || 0) - (b.order_index || 0))
              .map(it => ({
                id: it.id,
                name: it.name,
                type: it.type,
                time: it.time,
                note: it.note,
              }))
            : [],
        }));
    }

    return {
      id: plain.id,
      userId: plain.user_id,
      cityId: plain.city_id,
      cityName,
      title: plain.title,
      description: plain.description,
      startDate: plain.start_date,
      isPublic: !!plain.is_public,
      status: plain.status,
      coverImage: plain.cover_image,
      days: plain.days,
      is_top: !!plain.is_top,
      dailyPlans,
      created_at: plain.created_at,
      updated_at: plain.updated_at,
    };
  }
}

module.exports = TravelPlanService;